// watch for multiple inclusions
#ifndef MATH_DEFINE
#define MATH_DEFINE

#pragma warning(disable:4996)
#pragma warning(disable:4244)

// pi defines
#define PI         ((float)3.141592654f)
#define PI2        ((float)6.283185307f)
#define PI_DIV_2   ((float)1.570796327f)
#define PI_DIV_4   ((float)0.785398163f) 
#define PI_INV     ((float)0.318309886f) 

// fixed point mathematics constants
#define FIXP16_SHIFT     16
#define FIXP16_MAG       65536
#define FIXP16_DP_MASK   0x0000ffff
#define FIXP16_WP_MASK   0xffff0000
#define FIXP16_ROUND_UP  0x00008000

// bit manipulation macros
#define SET_BIT(word,bit_flag)   ((word)=((word) | (bit_flag)))
#define RESET_BIT(word,bit_flag) ((word)=((word) & (~bit_flag)))

// used to compute the min and max of two expresions
#define MIN(a, b)  (((a) < (b)) ? (a) : (b)) 
#define MAX(a, b)  (((a) > (b)) ? (a) : (b)) 

// used for swapping algorithm
#define SWAP(a,b,t) {t=a; a=b; b=t;}

// some math macros
#define DEG_TO_RAD(ang) ((ang)*PI/180.0)
#define RAD_TO_DEG(rads) ((rads)*180.0/PI)

#define RAND_RANGE(x,y) ( (x) + (rand()%((y)-(x)+1)))

// TYPES //////////////////////////////////////////////////

// basic unsigned types
typedef unsigned short USHORT;
typedef unsigned short WORD;
typedef unsigned char  UCHAR;
typedef unsigned char  BYTE;
typedef unsigned int   QUAD;
typedef unsigned int   UINT;

// a 2D vertex
typedef struct VERTEX2DI_TYP
{
	int x,y; // the vertex
} VERTEX2DI, *VERTEX2DI_PTR;

// a 2D vertex
typedef struct VERTEX2DF_TYP
{
	float x,y; // the vertex
} VERTEX2DF, *VERTEX2DF_PTR;

// a 2D polygon
typedef struct POLYGON2D_TYP
{
	int state;        // state of polygon
	int num_verts;    // number of vertices
	int x0,y0;        // position of center of polygon  
	int xv,yv;        // initial velocity
	DWORD color;      // could be index or PALETTENTRY
	VERTEX2DF *vlist; // pointer to vertex list

} POLYGON2D, *POLYGON2D_PTR;

// matrix defines

// 3x3 matrix /////////////////////////////////////////////
typedef struct MATRIX3X3_TYP
{
	union
	{
		float M[3][3]; // array indexed data storage

		// storage in row major form with explicit names
		struct
		{
			float M00, M01, M02;
			float M10, M11, M12;
			float M20, M21, M22;
		}; // end explicit names

	}; // end union
} MATRIX3X3, *MATRIX3X3_PTR;

// 1x3 matrix /////////////////////////////////////////////
typedef struct MATRIX1X3_TYP
{
	union
	{
		float M[3]; // array indexed data storage

		// storage in row major form with explicit names
		struct
		{
			float M00, M01, M02;

		}; // end explicit names
	}; // end union
} MATRIX1X3, *MATRIX1X3_PTR;

// 3x2 matrix /////////////////////////////////////////////
typedef struct MATRIX3X2_TYP
{
	union
	{
		float M[3][2]; // array indexed data storage

		// storage in row major form with explicit names
		struct
		{
			float M00, M01;
			float M10, M11;
			float M20, M21;
		}; // end explicit names

	}; // end union
} MATRIX3X2, *MATRIX3X2_PTR;

// 1x2 matrix /////////////////////////////////////////////
typedef struct MATRIX1X2_TYP
{
	union
	{
		float M[2]; // array indexed data storage

		// storage in row major form with explicit names
		struct
		{
			float M00, M01;

		}; // end explicit names
	}; // end union
} MATRIX1X2, *MATRIX1X2_PTR;

// error functions
int Open_Error_File(char *filename, FILE *fp_override=NULL);
int Close_Error_File(void);
int Write_Error(char *string, ...);

// math functions
int Fast_Distance_2D(int x, int y);
float Fast_Distance_3D(float x, float y, float z);

void Build_Sin_Cos_Tables(void);
int Translate_Polygon2D(POLYGON2D_PTR poly, int dx, int dy);
int Rotate_Polygon2D(POLYGON2D_PTR poly, int theta);
int Scale_Polygon2D(POLYGON2D_PTR poly, float sx, float sy);
int Translate_Polygon2D_Mat(POLYGON2D_PTR poly, int dx, int dy);
int Rotate_Polygon2D_Mat(POLYGON2D_PTR poly, int theta);
int Scale_Polygon2D_Mat(POLYGON2D_PTR poly, float sx, float sy);

int Mat_Mul_1X2_3X2(MATRIX1X2_PTR ma, 
	MATRIX3X2_PTR mb,
	MATRIX1X2_PTR mprod);

int Mat_Mul_1X3_3X3(MATRIX1X3_PTR ma, 
	MATRIX3X3_PTR mb,
	MATRIX1X3_PTR mprod);

int Mat_Mul_3X3(MATRIX3X3_PTR ma, 
	MATRIX3X3_PTR mb,
	MATRIX3X3_PTR mprod);

inline int Mat_Init_3X2(MATRIX3X2_PTR ma, 
	float m00, float m01,
	float m10, float m11,
	float m20, float m21);


// memory manipulation functions
inline void Mem_Set_WORD(void *dest, USHORT data, int count);
inline void Mem_Set_QUAD(void *dest, UINT   data, int count);

// INLINE FUNCTIONS //////////////////////////////////////////

inline void Mem_Set_WORD(void *dest, USHORT data, int count)
{
	// this function fills or sets unsigned 16-bit aligned memory
	// count is number of words

	//Write_Error("{");
	_asm 
	{ 
		mov edi, dest   ; edi points to destination memory
			mov ecx, count  ; number of 16-bit words to move
			mov ax,  data   ; 16-bit data
			rep stosw       ; move data
	} // end asm

	//Write_Error("}");

} // end Mem_Set_WORD

///////////////////////////////////////////////////////////

inline void Mem_Set_QUAD(void *dest, UINT data, int count)
{
	// this function fills or sets unsigned 32-bit aligned memory
	// count is number of quads

	_asm 
	{ 
		mov edi, dest   ; edi points to destination memory
			mov ecx, count  ; number of 32-bit words to move
			mov eax, data   ; 32-bit data
			rep stosd       ; move data
	} // end asm

} // end Mem_Set_QUAD

//////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////

inline int Mat_Init_3X2(MATRIX3X2_PTR ma, 
	float m00, float m01,
	float m10, float m11,
	float m20, float m21)
{
	// this function fills a 3x2 matrix with the sent data in row major form
	ma->M[0][0] = m00; ma->M[0][1] = m01; 
	ma->M[1][0] = m10; ma->M[1][1] = m11; 
	ma->M[2][0] = m20; ma->M[2][1] = m21; 

	// return success
	return(1);

} // end Mat_Init_3X2

// GLOBALS ////////////////////////////////////////////////
extern FILE *fp_error;                           // general error file
extern char error_filename[80];                  // error file name

// storage for our lookup tables
extern float cos_look[361]; // 1 extra so we can store 0-360 inclusive
extern float sin_look[361]; // 1 extra so we can store 0-360 inclusive

#endif
